home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / fish / 001-100 / 001-025 / 018 / amigadisplay / main.c < prev    next >
C/C++ Source or Header  |  1995-03-17  |  12KB  |  346 lines

  1. /* AmigaDisplay:  A "smart display" terminal emulator for the Amiga
  2.  *
  3.  * Based on the AmigaTerm program by Michael Mounier, enhanced by Don Woods.
  4.  * This version emulates either a "dumb terminal" or a DataMedia 2500.
  5.  * Mounier's version was (c) 1985 but was freely distributed.  Woods's
  6.  * rewrite is (c) 1986 and is likewise available if due credit is given.
  7.  *
  8.  * The DM2500 supports a special command sequence used at Stanford to display
  9.  * up to 128 different character glyphs, and also supports various special
  10.  * interpretations applied to the ALT, AMIGA, and F# keys (again for use at
  11.  * Stanford).  These features, and the type of display being emulated, should
  12.  * be fairly easy to change (e.g., if someone would rather emulate a VT100).
  13.  *
  14.  * The emulator also provides a variety of bell volumes (just for kicks), and
  15.  * file send/capture, but NOT the so-called "xmodem" features.  The send/
  16.  * capture stuff uses a requester to avoid mucking up the display region.
  17.  */
  18.  
  19. /****************************************\
  20. * This file is the main program (main.c) *
  21. \****************************************/
  22.  
  23. #include <exec/types.h>
  24. #include <exec/exec.h>
  25. #include <graphics/gfxbase.h>
  26. #include <graphics/gfx.h>
  27. #include <graphics/text.h>
  28. #include <devices/serial.h>
  29. #include <devices/keymap.h>
  30. #include <stdio.h>
  31. #include <intuition/intuitionbase.h>
  32. #include <intuition/intuition.h>
  33.  
  34. /*
  35.  * Library definitions; shared with the other modules
  36.  */
  37.  
  38. #define INTUITION_REV 1
  39. #define GRAPHICS_REV  1
  40. #define FONT_REV      1
  41.  
  42. struct IntuitionBase *IntuitionBase = NULL;
  43. struct GfxBase       *GfxBase       = NULL;
  44. struct DiskfontBase  *DiskfontBase  = NULL;
  45.  
  46. /*
  47.  * Functions imported from other modules
  48.  */
  49.  
  50. /* in intuit.c */
  51. extern InitWindowStuff(struct Window *);
  52. extern CleanUpWindow(struct Window *);
  53. extern FileMenu(struct Window *, int, FILE **, FILE **, int *);
  54.  
  55. /* in dpy.c */
  56. extern SetUpDisplay(struct Window *, int);
  57. extern char Emit(char);
  58. extern NeedQuote(char);
  59.  
  60. /* in beep.c */
  61. extern InitAudio(int);
  62. extern SetBeeper(int);
  63. extern Beep();
  64. extern CleanUpBeeper();
  65.  
  66. /*
  67.  * Globals and externals for using the serial port
  68.  */
  69.  
  70. extern struct MsgPort *CreatePort();
  71. static struct IOExtSer *inreq = NULL, *outreq = NULL;
  72. static char inbuf[2], outbuf[2];
  73.  
  74. /*
  75.  * MAIN PROGRAM
  76.  */
  77.  
  78. main() {
  79.    char c;
  80.    int buckied; /* see ToAsc for details */
  81.    int proceed = TRUE, fileFlags = 0; 
  82.    FILE *receive = NULL, *send = NULL;
  83.    struct Window *mywindow;
  84.    struct IntuiMessage *message; /* msg struct for GetMsg */
  85.  
  86.    /* Bits set in fileFlags */
  87.    #define RAWCAPTURE 1  /* include ctrl chars in captured file */
  88.    #define SENDLFASCR 2  /* translate LFs to CRs when sending */
  89.  
  90.    /* Emulator window structure */
  91.    static struct NewWindow newWindow = {
  92.       0, 0, 640, 200,
  93.       0,
  94.       1,
  95.       RAWKEY | MENUPICK | GADGETUP | REQCLEAR,
  96.       SMART_REFRESH | ACTIVATE | BORDERLESS,
  97.       NULL, NULL, NULL, NULL, NULL,
  98.       100, 35, 640, 200, /* min/max dims, unused since sizegadget omitted */
  99.       WBENCHSCREEN};
  100.  
  101.    IntuitionBase = (struct IntuitionBase *)
  102.       OpenLibrary("intuition.library", INTUITION_REV);
  103.    GfxBase = (struct GfxBase *)
  104.       OpenLibrary("graphics.library", GRAPHICS_REV);
  105.    DiskfontBase = (struct DiskfontBase *)
  106.       OpenLibrary("diskfont.library", FONT_REV);
  107.    if (IntuitionBase == NULL || GfxBase == NULL || DiskfontBase == NULL)
  108.       GoAway("Can't open libraries", NULL);
  109.  
  110.    if ((mywindow = (struct Window *)OpenWindow(&newWindow)) == NULL)
  111.       GoAway("Can't open window", NULL);
  112.  
  113.    /* Open serial device once and copy the initialised ioreq; */
  114.    /* that way we can have exclusive access with two ports    */
  115.  
  116.    inreq = (struct IOExtSer *)AllocMem(sizeof(*inreq), MEMF_PUBLIC|MEMF_CLEAR);
  117.    inreq->IOSer.io_Message.mn_ReplyPort = CreatePort("SerialRead", 0);
  118.    if (OpenDevice(SERIALNAME, NULL, inreq, NULL))
  119.       GoAway("Can't open Serial port", mywindow);
  120.  
  121.    inreq->io_SerFlags = SERF_SHARED | SERF_XDISABLED;
  122.    inreq->IOSer.io_Command = SDCMD_SETPARAMS;
  123.    inreq->io_ReadLen = inreq->io_WriteLen = 8;
  124.    DoIO(inreq);
  125.  
  126.    inreq->IOSer.io_Length = 1;
  127.    outreq = (struct IOExtSer *)AllocMem(sizeof(*outreq), MEMF_PUBLIC);
  128.    movmem((char *)inreq, (char *)outreq, sizeof(*inreq));
  129.    outreq->IOSer.io_Message.mn_ReplyPort = CreatePort("SerialWrite", 0);
  130.  
  131.    inreq->IOSer.io_Command = CMD_READ;
  132.    inreq->IOSer.io_Data = (APTR)inbuf;
  133.    outreq->IOSer.io_Command = CMD_WRITE;
  134.    outreq->IOSer.io_Data = (APTR)outbuf;
  135.  
  136.    if (InitWindowStuff(mywindow)) {
  137.       CloseDevice(inreq);
  138.       CloseDevice(outreq);
  139.       GoAway("Not enough memory", mywindow);
  140.       }
  141.  
  142.    /* Finish initialisation */
  143.    InitAudio(1);
  144.    SetAPen(mywindow->RPort, 1);
  145.    SetUpDisplay(mywindow, 1);
  146.    SetBaud(1);
  147.    BeginIO(inreq);
  148.  
  149.    while (proceed) {
  150.       /* wait for something to do */
  151.       if (send == NULL)
  152.          Wait((1 << inreq->IOSer.io_Message.mn_ReplyPort->mp_SigBit)
  153.             | (1 << mywindow->UserPort->mp_SigBit));
  154.       if (CheckIO(inreq)) { /* receive a char from the host */
  155.          WaitIO(inreq);
  156.          c = inbuf[0] & 0x7F;
  157.          BeginIO(inreq);
  158.          if (fileFlags & RAWCAPTURE) Emit(c); else c = Emit(c);
  159.          /* Emit returns hex 80 if char is non-printing */
  160.          if (receive != NULL && c < 0x80) /* capture this character */
  161.             if ((c >= ' ' && c <= '~') || c == '\n' || c == '\t')
  162.                putc(c, receive); /* always capture these chars */
  163.             else if (fileFlags & RAWCAPTURE) {
  164.                if (c == 0x7F) fputs("^?", receive);
  165.                else {putc('^', receive); putc(c+0x40, receive);}
  166.                }
  167.          }
  168.       else if (send != NULL) { /* send file (only if host not talking) */
  169.          if ((c=getc(send)) != EOF)
  170.             Ship(c == '\n' && (fileFlags & SENDLFASCR) ? '\r' : c);
  171.          else {
  172.             fclose(send);
  173.             send = NULL;
  174.             FileMenu(mywindow, 99, &receive, &send, &fileFlags);
  175.             }
  176.          }
  177.       while (message = (struct IntuiMessage *)GetMsg(mywindow->UserPort)) {
  178.          ULONG class;
  179.          USHORT code, qual;
  180.          class = message->Class;
  181.          code = message->Code;
  182.          qual = message->Qualifier;
  183.          ReplyMsg(message);
  184.          switch (class) {
  185.             case RAWKEY:  /* user has touched the keyboard */
  186.                if ((buckied = ToAsc(code, qual)) >= 0) {
  187.                   if (buckied & 0x100) Ship(0x80);
  188.                   else if (NeedQuote(c = buckied & 0x7F)) Ship(0);
  189.                   Ship(buckied & 0xFF);
  190.                   }
  191.                else if (buckied != -99) { /* function key */
  192.                   Ship(0); /* send NUL, number, CR */
  193.                   Ship('0'+((-buckied)/10));
  194.                   Ship('0'+((-buckied)%10));
  195.                   Ship('\r');
  196.                   }
  197.                break;
  198.             case MENUPICK:
  199.                if (code != MENUNULL) switch (MENUNUM(code)) {
  200.                   case 0: FileMenu(mywindow, ITEMNUM(code), &receive, &send, &fileFlags); break;
  201.                   case 1: BaudMenu(code); break;
  202.                   case 2: SetUpDisplay(NULL, ITEMNUM(code)); break;
  203.                   case 3:
  204.                      SetBeeper(ITEMNUM(code));
  205.                      if (Beep()) DisplayBeep(mywindow->WScreen);
  206.                      break;
  207.                   case 4: proceed = WindowMenu(mywindow, code); break;
  208.                   }
  209.                break;
  210.             } /* end of switch (class) */
  211.          } /* end of while (message) */
  212.       } /* end of while (proceed) */
  213.  
  214.    /* It must be time to quit */
  215.  
  216.    CloseDevice(inreq);
  217.    CloseDevice(outreq);
  218.    CleanUpWindow(mywindow);
  219.    CleanUpBeeper();
  220.    GoAway(NULL, mywindow); /* exit will close send/receive files if open */
  221.    } /* end of main */
  222.  
  223. /*
  224.  * Function to clean up however much stuff got started
  225.  */
  226.  
  227. static GoAway(text, w) char *text; struct Window *w; {
  228.    if (w) CloseWindow(w);
  229.    if (inreq) {
  230.       DeletePort(inreq->IOSer.io_Message.mn_ReplyPort);
  231.       FreeMem(inreq, sizeof(*inreq));
  232.       }
  233.    if (outreq) {
  234.       DeletePort(outreq->IOSer.io_Message.mn_ReplyPort);
  235.       FreeMem(outreq, sizeof(*outreq));
  236.       }
  237.    if (IntuitionBase != NULL) CloseLibrary(IntuitionBase);
  238.    if (GfxBase != NULL) CloseLibrary(GfxBase);
  239.    if (DiskfontBase != NULL) CloseLibrary(DiskfontBase);
  240.    if (text) {printf("ERROR: %s\n", text); exit(100);}
  241.    exit(FALSE);
  242.    }
  243.  
  244. /*
  245.  * Quickie to ship one char to serial port
  246.  */
  247.  
  248. static Ship(c) char c; {
  249.    outbuf[0] = c;
  250.    DoIO(outreq);
  251.    }
  252.  
  253. /*
  254.  * Menu routines (FileMenu is external)
  255.  */
  256.  
  257. static BaudMenu(code) USHORT code; {
  258.    AbortIO(inreq);
  259.    SetBaud(ITEMNUM(code));
  260.    BeginIO(inreq);
  261.    }
  262.  
  263. static SetBaud(index) USHORT index; {
  264.    switch (index) {
  265.       case 0: inreq->io_Baud = 300; break;
  266.       case 1: inreq->io_Baud = 1200; break;
  267.       case 2: inreq->io_Baud = 2400; break;
  268.       case 3: inreq->io_Baud = 4800; break;
  269.       case 4: inreq->io_Baud = 9600; break;
  270.       }
  271.    inreq->IOSer.io_Command = SDCMD_SETPARAMS;
  272.    DoIO(inreq);
  273.    inreq->IOSer.io_Command = CMD_READ;
  274.    }
  275.  
  276. static WindowMenu(w, code) struct Window *w; USHORT code; {
  277.    /* returns TRUE unless window is supposed to close */
  278.    switch (ITEMNUM(code)) {
  279.       case 0: WindowToBack(w); break;
  280.       case 1: WindowToFront(w); break;
  281.       case 2: return(FALSE);
  282.       }
  283.    return(TRUE);
  284.    }
  285.  
  286. /*
  287.  * Function to convert raw key data into ascii chars
  288.  */
  289.  
  290. /* The system at Stanford uses 9-bit characters.  The bottom 7 bits are normal
  291.  * ascii, although there are visible characters associated with the ctrl chars.
  292.  * (E.g., ^H prints as lambda, ^U as existential quantifier, ^A as down-arrow.)
  293.  * The 0x80 bit and 0x100 bit are called "bucky bits" (see Hacker's Dictionary)
  294.  * and are typically used to distinguish command chars from regular typein.
  295.  * These bits are set by some extra shift keys on the Stanford keyboards, called
  296.  * CONTROL and META.  When talking to Stanford across an 8-bit serial line,
  297.  * one sends CONTROL in the parity bit and META by a prefixed char (0x80).
  298.  * This emulator interprets ALT as CONTROL, AMIGA as META, and CTRL as the
  299.  * standard-ascii control key.  If you don't need the bucky-bit features, just
  300.  * don't hold down the ALT or AMIGA keys while typing, and you'll be fine.
  301.  * 
  302.  * This function returns the 7-bit ascii code for the given keyboard action,
  303.  * plus bucky-bits in 0x180.  If the keyboard action is a no-op (e.g., key up,
  304.  * or shift key down), it returns -99.  Function keys return -(10+key#), or
  305.  * -key# if shifted.
  306.  */
  307.  
  308. /* qualifier bits */
  309. #define LSHIFT  (1<<0)
  310. #define RSHIFT  (1<<1)
  311. #define SHLOCK  (1<<2)
  312. #define CTL     (1<<3) /* the real "ctrl" key */
  313. #define LCTRL   (1<<4) /* ALT keys set parity bit */
  314. #define RCTRL   (1<<5)
  315. #define LMETA   (1<<6) /* Amiga keys set 9th bit */
  316. #define RMETA   (1<<7)
  317.  
  318. static ToAsc(code, qual) USHORT code, qual; {
  319.    char c;
  320.    static char *map = "\
  321. `1234567890-=\\?0qwertyuiop[]?123asdfghjkl;'??456\
  322. ?zxcvbnm,./?.789 \b\t\n\r\33\177???-?\13\f";
  323.    if (code >= 0x50 && code <= 0x59) /* function keys */
  324.       return((qual & (LSHIFT|RSHIFT) ? -1 : -11) - (c = code&0xF));
  325.    if (code <= 0x4D) c = map[code];
  326.    else if (code == 0x5F) c = 0; /* HELP key translates into NUL */
  327.    else return(-99);
  328.    if (c == '?') return(-99);
  329.    if (qual & (LSHIFT|RSHIFT)) {
  330.       if (c >= 'a' && c <= 'z') c -= 0x20;
  331.       else if (c >= ',' && c <= '=') {
  332.          code = c - ','; /* sidestep compiler bug re subscript exprs */
  333.          c = "<_>?)!@#$%^&*(::<+"[code];
  334.          }
  335.       else if (c >= '[' && c <= '`') {
  336.          code = c - '['; /* ditto */
  337.          c = "{|}^_~"[code];
  338.          }
  339.       else if (c == '\'') c = '"';
  340.       } /* end shift */
  341.    else if ((qual & SHLOCK) && c >= 'a' && c <= 'z') c -= 0x20;
  342.    if (qual & CTL) c &= 0x1F;
  343.    return(c + (qual & (LCTRL|RCTRL) ? 0x80 : 0)
  344.       + (qual & (LMETA|RMETA) ? 0x100 : 0));
  345.    } /* end of ToAsc */
  346.